#![allow(dead_code)]

/// NOTE: 原始的、不安全的指针 *const T 和 *mut T。
struct PointerLrn {}

impl PointerLrn {
    pub fn hello() {
        println!("Pointer learning!");
    }
}

#[cfg(test)]
mod tests {
    #[test]
    /// 原始指针
    fn test_pointer_mut() {
        let mut my_speed: i32 = 88;
        let my_speed_ptr: *mut i32 = &mut my_speed;
        unsafe {
            *my_speed_ptr = 100;
        }
        assert_eq!(my_speed, 100);
    }

    #[test]
    /// Box指针
    fn test_box_pointer_mut() {
        let mut my_speed: Box<i32> = Box::new(88);
        let my_speed_ptr: *mut i32 = &mut *my_speed;
        unsafe {
            my_speed_ptr.write(100);
            *my_speed_ptr = 120;
        }
        assert_eq!(*my_speed, 120);
    }

    #[test]
    /// 指针宏 std::ptr::addr_of_mut!
    fn test_ptr_addr_of_mut() {
        #[derive(Debug, Default, Copy, Clone)]
        #[repr(C, packed)]
        struct S {
            aligned: u8,
            unaligned: u32,
        }
        let mut s = S::default();
        let p = std::ptr::addr_of_mut!(s.unaligned); // 不允许强制转换

        unsafe {
            p.write(999);
            // 不能用deref *p = 100;
        }

        println!("{:?}", s);
    }

    #[test]
    fn test_create_raw_pointer() {
        let mut x = 5;
        let raw = &x as *const i32;
        let mut_raw = &mut x as *mut i32;
        let points_at = unsafe { *raw };
        let mut_points_at = unsafe {
            *mut_raw = 8;
            *mut_raw
        };
        println!("raw = {:p}", raw);
        println!("mut_raw = {:p}", mut_raw);
        println!("points_at = {}", points_at);
        println!("mut_points_at = {}", mut_points_at);
    }

    #[test]
    fn test_convert_struct() {
        struct Foo {
            a: i32,
            b: i32,
        }

        #[derive(Debug)]
        struct Bar {
            a: i32,
            b: i32,
        }

        let f = Foo { a: 1, b: 2 };
        let b = unsafe { &*(&f as *const Foo as *const Bar) };
        println!("b = {:#?}", *b);
        println!("size of f: {:?}", std::mem::size_of_val(&f));
        println!("size of b: {:?}", std::mem::size_of_val(b));
        println!("f addr= {:p}", &f.a);
        println!("b addr= {:p}", &b.a);

        // try to modify `b` by pointer
        #[allow(invalid_reference_casting)]
        unsafe {
            let b: &mut Bar = &mut *(b as *const Bar as *mut Bar);
            b.a = 12;
            b.b = 4;
        }
        println!("b = {:#?}", b);
    }

    #[test]
    /// NOTE: 用指针修改结构体的值
    fn test_change_to_mut_struct() {
        #[derive(Debug)]
        pub struct Test {
            pub field: String,
        }

        impl Test {
            pub fn change(&self) {
                #[allow(invalid_reference_casting)]
                unsafe {
                    let mutable_t: &mut Test = &mut *(self as *const Self as *mut Self);
                    mutable_t.field = "changed".into();
                }
            }
        }

        let t = Test {
            field: "default".into(),
        };
        println!("{:?}", t);
        t.change();
        println!("{:?}", t);
    }

    #[test]
    /// 函数指针
    fn fn_pointer_test() {
        type MathOp = fn(i32, i32) -> i32;
        let add_pt: MathOp = add;

        let var = add_pt(11, 32);
        assert_eq!(var, 43);

        fn add(a: i32, b: i32) -> i32 {
            a + b
        }
    }
}
